/*
  Version: MPL 1.1/GPL 2.0/LGPL 2.1
 
  The contents of this file are subject to the Mozilla Public License Version
  1.1 (the "License"); you may not use this file except in compliance with
  the License. You may obtain a copy of the License at
  http://www.mozilla.org/MPL/
  
  Software distributed under the License is distributed on an "AS IS" basis,
  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  for the specific language governing rights and limitations under the
  License.
  
  The Original Code is [maashaack framework].
  
  The Initial Developers of the Original Code are
  Zwetan Kjukov <zwetan@gmail.com> and Marc Alcaraz <ekameleon@gmail.com>.
  Portions created by the Initial Developers are Copyright (C) 2006-2012
  the Initial Developers. All Rights Reserved.
  
  Contributor(s):
  
  Alternatively, the contents of this file may be used under the terms of
  either the GNU General Public License Version 2 or later (the "GPL"), or
  the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  in which case the provisions of the GPL or the LGPL are applicable instead
  of those above. If you wish to allow use of your version of this file only
  under the terms of either the GPL or the LGPL, and not to allow others to
  use your version of this file under the terms of the MPL, indicate your
  decision by deleting the provisions above and replace them with the notice
  and other provisions required by the LGPL or the GPL. If you do not delete
  the provisions above, a recipient may use your version of this file under
  the terms of any one of the MPL, the GPL or the LGPL.
*/

package air.desktop
{
    import flash.filesystem.File;
    import flash.filesystem.FileMode;
    import flash.filesystem.FileStream;
    import flash.system.Capabilities;

    /**
     * The enumeration of all known device models.
     */
    public class DeviceModel
    {
        //---- Known Device Models ----

        //Generic
        public static const unknown:DeviceModel            = new DeviceModel( "", "Unknown", "" );
        public static const desktop:DeviceModel            = new DeviceModel( "", "Desktop", "" );
        
        //Apple
        public static const iPodTouch4:DeviceModel         = new DeviceModel( "Apple", "iPod Touch 4th Generation", "iPod4,1" );
        public static const iPodTouch5:DeviceModel         = new DeviceModel( "Apple", "iPod Touch 5th Generation", "iPod5,1" );
        public static const iPhone3GS:DeviceModel          = new DeviceModel( "Apple", "iPhone 3GS", "iPhone2,1" );
        public static const iPhone4:DeviceModel            = new DeviceModel( "Apple", "iPhone 4", "iPhone3,1" );
        public static const iPhone4CDMA:DeviceModel        = new DeviceModel( "Apple", "iPhone 4", "iPhone3,2", "CDMA" );
        public static const iPhone4S:DeviceModel           = new DeviceModel( "Apple", "iPhone 4S", "iPhone4,1" );
        public static const iPhone5:DeviceModel            = new DeviceModel( "Apple", "iPhone 5", "iPhone5,1" );
        public static const iPad1:DeviceModel              = new DeviceModel( "Apple", "iPad 1st Generation", "iPad1,1", "Wifi" );
        public static const iPad2:DeviceModel              = new DeviceModel( "Apple", "iPad 2nd Generation", "iPad2,1", "Wifi" );
        public static const iPad2GSM:DeviceModel           = new DeviceModel( "Apple", "iPad 2nd Generation", "iPad2,2", "GSM" );
        public static const iPad2CDMAV:DeviceModel         = new DeviceModel( "Apple", "iPad 2nd Generation", "iPad2,3", "CDMAV" );
        public static const iPad2CDMAS:DeviceModel         = new DeviceModel( "Apple", "iPad 2nd Generation", "iPad2,4", "CDMAS" );
        public static const iPadMini:DeviceModel           = new DeviceModel( "Apple", "iPad Mini", "iPad2,5", "Wifi" );
        public static const iPad3:DeviceModel              = new DeviceModel( "Apple", "iPad 3rd Generation", "iPad3,1", "Wifi" );
        public static const iPad3CDMA:DeviceModel          = new DeviceModel( "Apple", "iPad 3rd Generation", "iPad3,2", "CDMA" );
        public static const iPad3GSM:DeviceModel           = new DeviceModel( "Apple", "iPad 3rd Generation", "iPad3,3", "GSM" );
        public static const iPad4:DeviceModel              = new DeviceModel( "Apple", "iPad 4th Generation", "iPad3,4", "Wifi" );
        
        //Google
        public static const Nexus7:DeviceModel             = new DeviceModel( "Google", "Nexus 7", "Nexus 7" );
        
        //Samsung
        public static const GalaxyS:DeviceModel            = new DeviceModel( "Samsung", "Galaxy S", "SGH-T959V", "4G" );
        public static const GalaxySFascinate:DeviceModel   = new DeviceModel( "Samsung", "Galaxy S Fascinate", "SGH-T959D", "3G+" );
        public static const GalaxySVibrant:DeviceModel     = new DeviceModel( "Samsung", "Galaxy S Vibrant", "SGH-T959" );
        public static const GalaxySFascinate4G:DeviceModel = new DeviceModel( "Samsung", "Galaxy S Fascinate", "SGH-T959P", "4G" );
        
        public static const GalaxyNote:DeviceModel = new DeviceModel( "Samsung", "Galaxy Note", "GT-N7000" );
        
        //HTC
        
        //Motorola
        
        //Sony
        
        //BlackBerry
        
        //---- Known Device Models ---- end
        
        
        /**
         * Returns the device model for a device type.
         */
        public static function findModelByDeviceType( device:String ):DeviceModel
        {
            const os:String = Capabilities.os;

              switch( device )
              {
                  case DeviceType.ipad:
                  case DeviceType.ipod:
                  case DeviceType.iphone:
                  return DeviceModel.findModelByIdentifier( Capabilities.os );
                  
                  case DeviceType.android:
                  return DeviceModel.findModelForAndroid();
                  
                  case DeviceType.desktop:
                  return DeviceModel.desktop;
                  
                  case DeviceType.unknow:
                  default:
                  return DeviceModel.unknown;
              }

            return DeviceModel.unknown;
        }

        /**
         * Returns the device model for a known identifier.
         */
        public static function findModelByIdentifier( identifier:String ):DeviceModel
        {
            /* TODO:
               allow to update this list with a custom list of value/pair
            */
            switch( identifier )
            {
                case "iPod4,1":
                return DeviceModel.iPodTouch4;

                case "iPod5,1":
                return DeviceModel.iPodTouch5;

                case "iPhone2,1":
                return DeviceModel.iPhone3GS;

                case "iPhone3,1":
                return DeviceModel.iPhone4;

                case "iPhone3,2":
                return DeviceModel.iPhone4CDMA;

                case "iPhone4,1":
                return DeviceModel.iPhone4S;

                case "iPhone5,1":
                return DeviceModel.iPhone5;

                case "iPad1,1":
                return DeviceModel.iPad1;

                case "iPad2,1":
                return DeviceModel.iPad2;

                case "iPad2,2":
                return DeviceModel.iPad2GSM;

                case "iPad2,3":
                return DeviceModel.iPad2CDMAV;

                case "iPad2,4":
                return DeviceModel.iPad2CDMAS;

                case "iPad2,5":
                return DeviceModel.iPadMini;

                case "iPad3,1":
                return DeviceModel.iPad3;

                case "iPad3,2":
                return DeviceModel.iPad3CDMA;

                case "iPad3,3":
                return DeviceModel.iPad3GSM;

                case "iPad3,4":
                return DeviceModel.iPad4;

                case "":
                default:
                return DeviceModel.unknown;
            }
        }

        /**
         * Returns the device model for a known Android device.
         */
        public static function findModelForAndroid():DeviceModel
        {
            /* note:
               example of build.prop file 
               ----
              # begin build properties
              # autogenerated by buildinfo.sh
              ro.build.id=FROYO
              ro.build.display.id=Bionix NextGen 1 by TeamWhiskey
              ro.build.version.incremental=UVKA6
              ro.build.version.sdk=8
              ro.build.version.codename=REL
              ro.build.version.release=2.2
              ro.build.date=2011. 01. 18. (화) 21:53:23 KST
              ro.build.date.utc=1295355203
              ro.build.type=user
              ro.build.user=jaeyoon.yoon
              ro.build.host=SEP-05
              ro.build.tags=release-keys
              ro.product.model=SGH-T959
              ro.product.brand=Samsung
              ro.product.name=SGH-T959
              ro.product.device=SGH-T959
              ro.product.board=SGH-T959
              ro.product.cpu.abi=armeabi-v7a
              ro.product.cpu.abi2=armeabi
              ro.product.manufacturer=Samsung
              ro.product.locale.language=en
              ro.product.locale.region=US
              ro.wifi.channels=
              ro.board.platform=s5pc110
              # ro.build.product is obsolete; use ro.product.device
              ro.build.product=SGH-T959
              # Do not try to parse ro.build.description or .fingerprint
              ro.build.description=SGH-T959-user 2.2 FROYO UVKA6 release-keys
              ro.build.fingerprint=Samsung/SGH-T959/SGH-T959/SGH-T959:2.2/FROYO/UVKA6:user/release-keys
              # Samsung Specific Properties
              ro.build.PDA=T959UVKA6
              ro.build.hidden_ver=T959UVKA6
              ro.build.changelist=860813
              ro.tether.denied=false
              # end build properties
               ----
            */
            var props:File = new File( "/system/build.prop" );

            if( props.exists )
            {
                var stream:FileStream = new FileStream();
                    stream.open( props, FileMode.READ );

                var data:String = stream.readUTFBytes( stream.bytesAvailable );
                    data = data.replace( File.lineEnding, "\n" );

                    stream.close();

                var pattern:RegExp = /\r?\n/;
                var lines:Array    = data.split( pattern );

                var i:uint;
                var line:String;
                var tmp:Array;
                var lhs:String;
                var rhs:String;

                for( i=0; i<lines.length; i++ )
                {
                    line = String( lines[ i ] );
                    if( line != "" )
                    {
                        tmp = line.split( "=" );
                        lhs = tmp[0].toLowerCase();
                        rhs = tmp[1];

                        /* note:
                           even if the doc mention "ro.build.product is obsolete; use ro.product.device"
                           we still need tochekc for the 2 properties
                        */
                        if( (lhs == "ro.product.device") || (lhs == "ro.build.product") )
                        {
                            /* TODO:
                               allow to update this list with a custom list of value/pair
                            */
                            switch( rhs )
                            {
                                case "SGH-T959V":
                                return DeviceModel.GalaxyS;

                                case "SGH-T959D":
                                return DeviceModel.GalaxySFascinate;

                                case "SGH-T959":
                                return DeviceModel.GalaxySVibrant;

                                case "SGH-T959P":
                                return DeviceModel.GalaxySFascinate4G;

                                case "GT-N7000":
                                case "GT-N7000B":
                                return DeviceModel.GalaxyNote;
                            }
                        }
                        /* note:
                           for other some special case we also need to check "ro.product.model"
                           yeah like on the "Nexus 7" which does not respect the doc above
                           go figures ?!?
                        */
                        else if( lhs == "ro.product.model" )
                        {
                            /* TODO:
                               allow to update this list with a custom list of value/pair

                               for ex:
                               public class DeviceModel2
                               {
                                    public static const test:DeviceModel = new DeviceModel( "", "Test", "XYZ" );
                               }

                               DeviceModel.addDefinition( DeviceModel2, "ro.product.device" );
                               DeviceModel.addDefinition( DeviceModel2, "ro.build.product" );
                               DeviceModel.addDefinition( DeviceModel2, "ro.product.model" );
                            */
                            switch( rhs )
                            {
                                case "Nexus 7":
                                return DeviceModel.Nexus7;
                            }
                        }
                    }
                }
            }
            else
            {
                return DeviceModel.unknown;
            }

            return DeviceModel.unknown;
        }
        
        /** @private */
        private var _vendor:String;
        
        /** @private */
        private var _name:String;
        
        /** @private */
        private var _identifier:String;
        
        /** @private */
        private var _options:String;

        /**
         * Creates a device model instance.
         */
        public function DeviceModel( vendor:String, name:String, identifier:String, options:String = null )
        {
            _vendor     = vendor;
            _name       = name;
            _identifier = identifier;

            if( options )
            {
                _options = options;
            }
        }

        /** The vendor name (not necessary the manufacturer or the brand). */
        public function get vendor():String { return _vendor; }
        
        /** The name of the model. */
        public function get name():String { return _name; }
        
        /** The identifier. */
        public function get identifier():String { return _identifier; }

        /**
         * Returns the string of the device model.
         */
        public function toString():String
        {
            var str:String = "";

            if( _vendor && (_vendor != "") )
            {
                str += _vendor;
                str += " ";
            }
                
                str += _name;

            if( _options )
            {
                str += " (" + _options +")";
            }

            return str;
        }
    }
}